package middleware

import (
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"runtime/debug"
	"strings"
	"time"
)

//import (
//	"fmt"
//	"github.com/gin-gonic/gin"
//	"github.com/sirupsen/logrus"
//	"math"
//	"os"
//	"time"
//)
//
//const (
//	all    = "all"
//	info   = "info"
//	errors = "errors"
//)
//
//var logPath = "D:\\go\\src\\ginblog\\logs\\Logs"
//
//func Logger() gin.HandlerFunc {
//	//logger := logrus.New()
//
//	//添加debug、info、warn、error四个日志级别的handler，分别输出到不同的文件中
//	allfile, err := os.OpenFile(fmt.Sprintf("%s/%s.log", logPath, all), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
//	if err != nil {
//		fmt.Println("err:", err)
//	}
//	logger := logrus.New()
//	logger.Out = allfile
//
//	errfile, err := os.OpenFile(fmt.Sprintf("%s/%s.log", logPath, errors), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
//	if err != nil {
//		fmt.Println("err:", err)
//	}
//	logger = logrus.New()
//	logger.Out = errfile
//
//	infofile, err := os.OpenFile(fmt.Sprintf("%s/%s.log", logPath, info), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
//	if err != nil {
//		fmt.Println("err:", err)
//	}
//	logger = logrus.New()
//	logger.Out = infofile
//
//	return func(c *gin.Context) {
//		startTime := time.Now()
//		//继续处理请求
//		c.Next()
//		endTime := time.Since(startTime)
//		spendTime := fmt.Sprintf("%dms", int(math.Ceil(float64(endTime.Nanoseconds())/1000000.0)))
//		hostName, err := os.Hostname()
//		if err != nil {
//			hostName = "unknown"
//		}
//		//请求的状态码
//		statusCode := c.Writer.Status()
//		//请求的ip
//		clientIp := c.ClientIP()
//		//	浏览器类型
//		userAgent := c.Request.UserAgent()
//		dataSize := c.Writer.Size()
//		if dataSize < 0 {
//			dataSize = 0
//		}
//		//请求方法
//		method := c.Request.Method
//		//请求的路径
//		path := c.Request.RequestURI
//		entry := logger.WithFields(logrus.Fields{
//			"HostName":  hostName,
//			"Status":    statusCode,
//			"SpendTime": spendTime,
//			"Ip":        clientIp,
//			"Method":    method,
//			"Path":      path,
//			"DataSize":  dataSize,
//			"Agent":     userAgent,
//		})
//
//		if len(c.Errors) > 0 {
//			//记录系统内部错误
//			entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String())
//		}
//		if statusCode >= 500 {
//			entry.Error()
//		} else if statusCode >= 400 {
//			entry.Warn()
//		} else {
//			entry.Info()
//		}
//	}
//}
//import (
//	"fmt"
//	"github.com/gin-gonic/gin"
//	retalog "github.com/lestrrat-go/file-rotatelogs"
//	"github.com/rifflock/lfshook"
//	"github.com/sirupsen/logrus"
//	"os"
//	"time"
//)
//
//func LogMiddleware() gin.HandlerFunc {
//	var filePath = "./log/log"
//	//linkName := "latest_log.log" 只适用于linux
//	scr, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0755)
//	if err != nil {
//		fmt.Println("err:", err)
//	}
//	logger := logrus.New()
//
//	logger.Out = scr
//
//	logger.SetLevel(logrus.DebugLevel)
//
//	logWriter, _ := retalog.New(
//		filePath+"%Y%m%d.log",
//		retalog.WithMaxAge(7*24*time.Hour),
//		retalog.WithRotationTime(24*time.Hour),
//		//retalog.WithLinkName(linkName), 只适用于linux
//	)
//
//	writeMap := lfshook.WriterMap{
//		logrus.InfoLevel:  logWriter,
//		logrus.FatalLevel: logWriter,
//		logrus.DebugLevel: logWriter,
//		logrus.WarnLevel:  logWriter,
//		logrus.ErrorLevel: logWriter,
//		logrus.PanicLevel: logWriter,
//	}
//	Hook := lfshook.NewHook(writeMap, &logrus.TextFormatter{
//		TimestampFormat: "2006-01-02 15:04:05",
//	})
//
//	logger.AddHook(Hook)
//
//	return func(c *gin.Context) {
//		startTime := time.Now()
//		c.Next()
//		stopTime := time.Since(startTime).Milliseconds()
//		spendTime := fmt.Sprintf("%dms", stopTime)
//		hostName, err := os.Hostname()
//		if err != nil {
//			hostName = "unknown"
//		}
//		statusCode := c.Writer.Status()
//		clientIp := c.ClientIP()
//		userAgent := c.Request.UserAgent()
//		dataSize := c.Writer.Size()
//		if dataSize < 0 {
//			dataSize = 0
//		}
//		method := c.Request.Method
//		path := c.Request.RequestURI
//
//		entry := logger.WithFields(logrus.Fields{
//			"HostName":  hostName,
//			"status":    statusCode,
//			"SpendTime": spendTime,
//			"Ip":        clientIp,
//			"Method":    method,
//			"Path":      path,
//			"DataSize":  dataSize,
//			"Agent":     userAgent,
//		})
//		if len(c.Errors) > 0 {
//			entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String())
//		}
//		if statusCode >= 500 {
//			entry.Error()
//		} else if statusCode >= 400 {
//			entry.Warn()
//		} else {
//			entry.Info()
//		}
//	}
//}
/*
	基于zap日志库实现接收gin框架默认输出的日志
*/
func GinLogger(logger *zap.Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		path := c.Request.URL.Path
		query := c.Request.URL.RawQuery
		c.Next()
		cost := time.Since(start)
		logger = zap.L().With(
			zap.Int("status", c.Writer.Status()),
			zap.String("method", c.Request.Method),
			zap.String("path", path),
			zap.String("query", query),
			zap.String("ip", c.ClientIP()),
			zap.String("user-agent", c.Request.UserAgent()),
			zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
			zap.Duration("cost", cost),
		)
		if len(c.Errors) > 0 {
			logger.Error(c.Errors.String())
		} else {
			logger.Info("")
		}
	}
}

// GinRecovery recover掉项目可能出现的panic
func GinRecovery(logger *zap.Logger, stack bool) gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if err := recover(); err != nil {
				// Check for a broken connection, as it is not really a
				// condition that warrants a panic stack trace.
				var brokenPipe bool
				if ne, ok := err.(*net.OpError); ok {
					if se, ok := ne.Err.(*os.SyscallError); ok {
						if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
							brokenPipe = true
						}
					}
				}

				httpRequest, _ := httputil.DumpRequest(c.Request, false)
				if brokenPipe {
					logger.Error(c.Request.URL.Path,
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
					)
					// If the connection is dead, we can't write a status to it.
					c.Error(err.(error)) // nolint: errcheck
					c.Abort()
					return
				}

				if stack {
					logger.Error("[Recovery from panic]",
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
						zap.String("stack", string(debug.Stack())),
					)
				} else {
					logger.Error("[Recovery from panic]",
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
					)
				}
				c.AbortWithStatus(http.StatusInternalServerError)
			}
		}()
		c.Next()
	}
}
